/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __ICAMERA_H__
#define __ICAMERA_H__

#pragma once

#include "geom/Vector.h"
#include "geom/Quaternion.h"
#include "IResource.h"
#include "Frustum.h"

/**
 * \ingroup CoreEngine
 *
 * The ICamera interface.<br>
 * Cameras are used to display something inside a scene.<br>
 * A default camera is created in the IRenderer interface and can be retrieved using IRenderer::getCamera().<br>
 * A camera must be renderered at the begining of a draw cycle using IRenderer::drawCamera().<br>
 * 
 * \date 03-28-2007
 *
 * \author juckel
 *
 * \todo Rotation around an arbitrary axis around the camera target.
 *
 */
class DLL_EXPORT ICamera 
	:	public IResource, 
		public Frustum
{
public:
	/// Creates a new camera other than the default camera, that can be used for different render targets
	static ICamera* Create();
	
	/// Detroys the camera
	virtual ~ICamera(void);

	/// Sets the camera inside the draw loop
	virtual void draw() = 0;

	/// Sets up the projection matrix for that camera
	virtual void setupProjection(float fov, float aspect, float znear, float zfar) = 0;

	/// Updating the clipping planes
	virtual void setClippingPlanes( float zNear, float zFar) = 0;

	/// Rotate the camera
	virtual void rotate(const math::Quaternion &q);

	virtual void resetAll();

	/// Rotate the camera around the target
	virtual void rotateAroundTarget(float h, float v);

	/// Move from/to target
	virtual void moveAlongViewVec(float z);
	
	/// Set the position in circle
	virtual void set_hRadians(float h);

	/// Set the position of the camera
	void setPosition(const math::Vector3 &vector);

	/// Set the target of the camera
	void setTarget(const math::Vector3 &vector);
	
	/// Set the vector pointing up for the camera
	void setUpVec(const math::Vector3 &vector);

	/// Returns the position of the camera
	const math::Vector3& getPosition() const;

	/// Returns the target of the camera
	const math::Vector3& getTarget() const;

	/// Returns the vector pointing up of the camera
	const math::Vector3& getUpVec() const;

	virtual void setOrtho(bool on);

	virtual void reset() {};
	virtual void release() {};

	//void setClippingPlanes( float zNear, float zFar);
	float getAspect(){ return fAspect;};
	float getFov(){ return fFov;};

	math::Matrix4 getViewMatrix();
	math::Matrix4 getProjMatrix();
	float* calculateConvexHull( );

	virtual unsigned int getType() { return RESTYPE_CAMERA; };
	float getHRadians(){return hRadians;}
	float getVRadians(){return vRadians;}

protected:
	ICamera(void);

	virtual void updateMatrix() = 0;

	math::Matrix4 matView;
	math::Matrix4 matProj;

	math::Vector3 vPosition;		///< The current position
	math::Vector3 vTarget;			///< The current target
	math::Vector3 vUpVec;			///< The current vector pointing up
	float hRadians, vRadians;
	
	float fZNear;				///< Near clipping plane
	float fZFar;				///< Far clipping plane
	float fFov;				///< Field of vision
	float fAspect;				///< Aspect ration
	bool m_bOrtho;				///< Indicates if this camera uses orthographic projection
};

#endif
